#include "PS2MOUSE.h"

uint8_t i=0;
uint8_t mask[] ={0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

uint8_t mouseStatus =  0;
//0 : no activity
//1 : falling edge handled
//2 : rising edge handled
//Introduces delay in case of parity error
uint8_t mouseData = 0; //received data will be stored here temp
uint8_t mouseIndex = 0; //progress
uint8_t mouseFlag=0; //1: data is received  2: Parity not matched
uint8_t mouseScroll=0;//0: Scroll disabled  1: Scroll enabled get byte 4

uint8_t oddParity(uint8_t byte)
{
	uint8_t i , count = 0;
	for(i=0 ; i<8 ; i++)
	{
		if(mask[i] & byte) count++;
	}
	return ((count+1)%2) ;
}
void releaseClockMouse()
{
	PS2_DDR&=~(1<<MCLK);  // 0 - input
	PS2_PORT|=(1<<MCLK);  // 1 - clock line high
}
void releaseDataMouse()
{
	PS2_DDR&=~(1<<MDATA); // 0 - input
	PS2_PORT|=(1<<MDATA); // 1 - data line high
}
void holdClockMouse()
{
	PS2_DDR|=(1<<MCLK);	  // 1 - output
	PS2_PORT&=~(1<<MCLK); // 0 - clock line low
}
void holdDataMouse()
{
	PS2_DDR|=(1<<MDATA);  // 1 - output
	PS2_PORT&=~(1<<MDATA);// 0 - data line low
}
void readMouse()
{
	if(mouseStatus==0 && bit_is_clear(PS2_DDR,MCLK) && bit_is_clear(PS2_PIN,MCLK) && bit_is_clear(PS2_DDR,MDATA) && bit_is_clear(PS2_PIN,MDATA)) //if inactive and start bit is there
	{
		mouseStatus = 1; //start bit received
		mouseIndex = 0;  //initialize
		mouseData = 0;   //initialize
		mouseFlag = 0;   //initialize
	}
	//if falling edge handled
	//look for rising edge and handle it
	else if(mouseStatus==1 && bit_is_clear(PS2_DDR,MCLK) && bit_is_set(PS2_PIN,MCLK))
	{
		mouseStatus = 2;
	}
	//if rising edge handled
	//look for falling edge and handle it
	//data is scanned at falling edge
	else if(mouseStatus==2 && bit_is_clear(PS2_DDR,MCLK) && bit_is_clear(PS2_PIN,MCLK))
	{
		if(mouseIndex<8 && bit_is_set(PS2_PIN,MDATA)) mouseData += (mask[mouseIndex]);
		mouseIndex++;
		mouseStatus = 1;
	}
	// stop bit
	if(mouseIndex>9) //all eight bytes have been received AND stp bit gone
	{
		mouseStatus = 0;
		mouseIndex = 0;
		//processMouseData();
		mouseFlag=1;
	}
}
void writeMouse(uint8_t cmd)
{
	//Release both the lines
	releaseDataMouse();
	releaseClockMouse();
	//Bring Clock line low for at least 100 uS
	holdClockMouse();
	_delay_us(120);             //may not be working now it may be
	//Bring the Data line low
	holdDataMouse();
	//Release the Clock line
	releaseClockMouse();
	// wait for the clock high

	while(bit_is_clear(PS2_PIN,MCLK));
	for(i=0 ; i<=MDATA ; i++) //8 data bits
	{
		//Wait for device to bring the clock low
		while(bit_is_set(PS2_PIN,MCLK));
		//Set the data bit
		if(cmd & mask[i]) /*== 1)*/ releaseDataMouse();  //CCCHHHHAAANGED
		else holdDataMouse();
		//Wait for devise to bring the clock high
		while(bit_is_clear(PS2_PIN,MCLK));
	}
	//Wait for devise to bring the clock low
	while(bit_is_set(PS2_PIN,MCLK));
	//Set the parity
	if(oddParity(cmd)==1)                            //try reversing the parity
	{
		releaseDataMouse();
	}
	else
	{
		holdDataMouse();
	}
	//Wait for devise to bring the clock high
	while(bit_is_clear(PS2_PIN,MCLK));
	//Wait for device to bring the clock low
	while(bit_is_set(PS2_PIN,MCLK));
	//Release the data line
	releaseDataMouse();
	//wait for clock high
	while(bit_is_clear(PS2_PIN,MCLK));
	//Wait for device to bring data low
	while(bit_is_set(PS2_PIN,MDATA));
	//Wait for device to bring clock low
	while(bit_is_set(PS2_PIN,MCLK));
	//Wait for device to release clock and data
	while(bit_is_clear(PS2_PIN,MCLK) || bit_is_clear(PS2_PIN,MDATA));

}


void mouseInit()
{
	mouseX = 0;
	mouseY = 0;
	mouseZ = 0;
	isLeft = 0;
	isRight = 0;
	isMiddle = 0;
	

	releaseDataMouse();
	releaseClockMouse();

	while(1)
	{
		//_delay_ms(10); //just for the sake of delay
		//reset command
		writeMouse(0xFF);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		//receive 0xAA - self test passed
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xAA) mouseFlag=0;


		else continue;
		//receive 0x00 - device ID
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0x00) mouseFlag=0;
		else continue;



		//Set Sample Rate 200--------------------------
		writeMouse(0xF3);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		// to 200 (0xC8)
		writeMouse(0xC8);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;

		//Set Sample Rate 100---------------------------
		writeMouse(0xF3);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		// to 100 (0x64)
		writeMouse(0x64);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;

		//Set Sample Rate 80----------------------------
		writeMouse(0xF3);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		// to 80  (0x50)
		writeMouse(0x50);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;

		//Check Device Type-----------------------------
		writeMouse(0xF2);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		//receive Mouse id - if 0x03 scroll is enabled
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0x03) mouseFlag=0,mouseScroll=1;
		else if(mouseFlag==1 && mouseData==0x00) mouseFlag=0,mouseScroll=0;
		else continue;



		//Set Sample Rate to default 100----------------
		writeMouse(0xF3);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		// to 100  (0x64)
		writeMouse(0x64);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;


		//Enter remote mode
		writeMouse(0xF0);
		//receive 0xFA - acknowledgment
		while(!mouseFlag) readMouse();
		if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
		else continue;
		break;
	}
}
void scanMouse()
{
	//stores data from mouse
	uint8_t byte1 = 0;
	uint8_t byte2 = 0;
	uint8_t byte3 = 0;
	uint8_t byte4 = 0;

	writeMouse(0xEB); //get data from mouse
	while(!mouseFlag) readMouse();
	if(mouseFlag==1 && mouseData==0xFA) mouseFlag=0;
	else return;
	
	while(!mouseFlag) readMouse();
	
	if(mouseFlag==1)
	{
		byte1 = mouseData;
		mouseFlag=0;
	}
	else {
		if(mouseFlag==2)
		return;
	}
	
	while(!mouseFlag) readMouse();
	
	if(mouseFlag==1)
	{
		byte2 = mouseData;
		mouseFlag=0;
	}
	else  return;
	
	while(!mouseFlag) readMouse();
	
	if(mouseFlag==1)
	{
		byte3 = mouseData;
		mouseFlag=0;
	}
	else return;

	if(mouseScroll){
		while(!mouseFlag) readMouse();
		
		if(mouseFlag==1)
		{
			byte4 = mouseData;
			mouseFlag=0;
		}
		else return;
	}

	
	//Byte processing
	if(byte1 & 0x01) isLeft=1;
	else isLeft=0;
	if(byte1 & 0x02) isRight=1;
	else isRight=0;
	if(byte1 & 0x04) isMiddle=1;
	else isMiddle=0;
	
	if(!(byte1 & 0x10)) //+ve X movement
	{
		//if(x_limit-byte2 > mouseX) mouseX += byte2;
		//else mouseX = x_limit; //mouse reached end of the screen
		mouseNewX=byte2;
		mouseX += mouseNewX;
	}
	else				//-ve X movement
	{
		//if(255-byte2+1 < mouseX) mouseX -= (255-byte2+1);
		//else mouseX = 0; //mouse reached begining of the screen
		mouseNewX=(255-byte2+1);
		mouseX -= mouseNewX;
	}
	
	if(!(byte1 & 0x20)) //+ve Y movement
	{
		//if(y_limit-byte3 > mouseY) mouseY += byte3;
		//else mouseY = y_limit; //mouse reached end of the screen
		mouseNewY=byte3;
		mouseY += mouseNewY;
	}
	else				//-ve Y movement
	{
		//if(255-byte3+1 < mouseY) mouseY -= (255-byte3+1);
		//else mouseY = 0; //mouse reached begining of the screen
		mouseNewY=(255-byte3+1);
		mouseY -= mouseNewY;
	}

	if(!(byte4 & 0x08)) //+ve Z movement (only the lower nibble represents the Z movements)
	{
		//if(x_limit-byte4 > mouseZ) mouseZ += byte4;
		//else mouseZ = z_limit; //mouse reached end of the screen
		mouseNewZ=byte4;
		mouseZ += mouseNewZ;
	}
	else				//-ve Z movement
	{
		//if(255-byte4+1 < mouseZ) mouseZ -= (255-byte4+1);
		//else mouseZ = 0; //mouse reached begining of the screen
		mouseNewZ=(255-byte4+1);
		mouseZ -= mouseNewZ;
	}

}